// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html


const {ccclass, property, requireComponent, executeInEditMode} = cc._decorator;

export enum EDirection {
    None,
    Forward,
    Backward,
}

interface IDisplay {
    left : cc.Sprite,
    right: cc.Sprite,
}

enum EDisplayPart {
    Left,
    Right,
}




@ccclass
// @requireComponent(cc.Sprite)
export default class TurnPage extends cc.Component {

    @property(cc.Camera)
    camera:cc.Camera = null;

    // @property(cc.Sprite)
    // sprLeftA:cc.Sprite = null;

    // @property(cc.Sprite)
    // sprRightA:cc.Sprite = null;

    // @property(cc.Sprite)
    // sprLeftB:cc.Sprite = null;

    // @property(cc.Sprite)
    // sprRightB:cc.Sprite = null;


    private _direction:EDirection = EDirection.None;

    private _dpMainPage:IDisplay = null; // 主显示的页
    private _dpTurnPage:IDisplay = null; // 翻页时翻动的页

    private _curPageNode:cc.Node = null;
    private _curRT:cc.RenderTexture = new cc.RenderTexture();

    private _newPageNode:cc.Node = null;
    private _newRT:cc.RenderTexture = new cc.RenderTexture();

    private _angle:number = 0;

    get turnAngle():number {
        // if(!this._dpTurnPage)
        //     return 0;
        // let q = new cc.Quat();
        // this._dpTurnPage.left.node.getRotation(q)
        // let v = new cc.Vec3();
        // cc.Quat.toEuler(v, q);
        // return v.y;
        return this._angle;
    }

    set turnAngle(val:number) {
        if(!this._dpTurnPage)
            return;

        // this.node.getRotation()

        val = Math.min(Math.max(val, 0), 180);

        // let r = (val * cc.macro.RAD) * 0.5;
        // let q = new cc.Quat(0, Math.sin(r), 0, Math.cos(r));

        // let eulerLeft = this._dpTurnPage.left.node.eulerAngles;
        // this._dpTurnPage.left.node.eulerAngles.set(new cc.Vec3(eulerLeft.x, val, eulerLeft.z));
        // this._dpTurnPage.left.node.setRotation(r);
        // this._dpTurnPage.left.node.eulerAngles.y = val;

        // let delta = val - this._angle;

        // let qLeft = new cc.Quat();
        // this._dpTurnPage.left.node.getRotation(qLeft);
        // let rLeft = delta * cc.macro.RAD;
        // cc.Quat.rotateY(qLeft, qLeft, rLeft);
        // this._dpTurnPage.left.node.setRotation(qLeft);

        let quadLeft = new cc.Quat();
        cc.Quat.fromEuler(quadLeft, 0, val, 0);
        this._dpTurnPage.left.node.setRotation(quadLeft);

        // r = ((180-val) * cc.macro.RAD) * 0.5;
        // q = new cc.Quat(0, Math.sin(r), 0, Math.cos(r));
        // let eulerRight = this._dpTurnPage.right.node.eulerAngles;
        // this._dpTurnPage.right.node.eulerAngles.set(new cc.Vec3(eulerRight.x, val - 180, eulerRight.z));
        // this._dpTurnPage.right.node.setRotation(q);
        // this._dpTurnPage.right.node.eulerAngles.y = val - 180;

        // let deltaRight = (val-180) - (this._angle - 180);
        // let qRight = new cc.Quat();
        // this._dpTurnPage.right.node.getRotation(qRight);
        // let rRight = (deltaRight * cc.macro.RAD);
        // cc.Quat.rotateY(qRight, qRight, rRight);
        // this._dpTurnPage.right.node.setRotation(qRight);

        let quadRight = new cc.Quat();
        cc.Quat.fromEuler(quadRight, 0, val - 180, 0);
        this._dpTurnPage.right.node.setRotation(quadRight);

        this._angle = val;
    }


    private buildDisplayPart(part:EDisplayPart):cc.Sprite {
        let node = new cc.Node();
        node.is3DNode = true;

        let spr = node.addComponent(cc.Sprite);
        // rt && (spr.spriteFrame = new cc.SpriteFrame(rt));
        spr.spriteFrame = new cc.SpriteFrame();
        spr.spriteFrame.setFlipY(true);

        let mat = cc.Material.getBuiltinMaterial(<any>cc.Material.BUILTIN_NAME.SPRITE);
        mat.setCullMode(1, 0);
        spr.setMaterial(0, mat);

        let widget = node.addComponent(cc.Widget);
        widget.isAlignTop = widget.isAlignBottom = widget.isAlignLeft = widget.isAlignRight = true;
        widget.top = widget.bottom = 0;

        // let halfW = width >> 1, halfH = height >> 1;

        switch(part) {
            case EDisplayPart.Left: {
                node.name = "left";
                node.anchorX = 1;

                // spr.spriteFrame.setRect(new cc.Rect(0, 0, halfW, halfH));

                widget.left = 0;
                widget.isAbsoluteRight = false;
                widget.right = 0.5;
            }
            break;
            case EDisplayPart.Right : {
                node.name = "right";
                node.anchorX = 0;
    
                // spr.spriteFrame.setRect(new cc.Rect(halfW, 0, halfW, halfH));
    
                widget.right = 0;
                widget.isAbsoluteLeft = false;
                widget.left = 0.5;
            }
        }

        this.node.addChild(node);

        return spr;
    }

    private updateDpPart(dp:IDisplay, tex:cc.RenderTexture, part:EDisplayPart) {
        if(!dp || !tex)
            return;

        let texW = tex.width >> 1, texH = tex.height;
        switch(part) {
            case EDisplayPart.Left:
                dp.left.spriteFrame.setTexture(tex, new cc.Rect(0, 0, texW, texH));
                dp.left['_updateMaterial']();
                break;
            case EDisplayPart.Right:
                dp.right.spriteFrame.setTexture(tex, new cc.Rect(texW, 0, texW, texH));
                dp.right['_updateMaterial']();
                break;
        }
    }

    private resizeRenderTexture(width:number, height:number) {
        this._curRT.initWithSize(width, height, 36168/*gl.STENCIL_INDEX8*/);
        this._newRT.initWithSize(width, height, 36168/*gl.STENCIL_INDEX8*/);
    }

    onLoad () {
        let width = this.node.width, height = this.node.height;

        this._curRT.name = "Cur";
        this._newRT.name = "New";

        this.resizeRenderTexture(width, height)

        this._dpMainPage = {
            left : this.buildDisplayPart(EDisplayPart.Left),
            right : this.buildDisplayPart(EDisplayPart.Right),
        }

        this._dpTurnPage = {
            left : this.buildDisplayPart(EDisplayPart.Left),
            right : this.buildDisplayPart(EDisplayPart.Right),
        }

        let camera = this.camera;
        if(camera) {
            // camera.targetTexture = this._rtFront;
            camera.enabled = false;
        }

        this.node.on(cc.Node.EventType.SIZE_CHANGED, this.onSizedChanged, this);
        cc.director.on(cc.Director.EVENT_BEFORE_DRAW, this.onBeforeDraw, this);
    }

    private onSizedChanged() {
        let width = this.node.width, height = this.node.height;

        this.resizeRenderTexture(width, height);

        // this._rtFront.initWithSize(this.node.width, this.node.height, 36168/*gl.STENCIL_INDEX8*/);
        // this.camera && (this.camera.targetTexture = this._rtFront);
    }

    private onBeforeDraw() {
        let camera = this.camera;
        if(!camera) return;

        camera.enabled = true;


        if(this._curPageNode) {
            camera.targetTexture = this._curRT;
            camera.render(this._curPageNode);
        }

        if(this._newPageNode) {
            camera.targetTexture = this._newRT;
            camera.render(this._newPageNode);
        }

        camera.enabled = false;
    }

    init(page:cc.Node = null) {
        this._direction = EDirection.None;

        this._dpTurnPage.left.node.active = false;
        this._dpTurnPage.right.node.active = false;

        this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Left);
        this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Right);

        this._curPageNode = page;
        this._newPageNode = null;
    }

    turnBeg(dir:EDirection, page:cc.Node) {
        if(this._direction !== EDirection.None)
            return;

        if(!page)
            return;

        this._newPageNode  = page;
        this._direction = dir;

        this._dpTurnPage.left.node.active = true;
        this._dpTurnPage.right.node.active = true;
        switch(dir) {
            case EDirection.Forward: {
                // 当前页
                this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Left);
                this.updateDpPart(this._dpTurnPage, this._curRT, EDisplayPart.Right);

                // 新一页
                this.updateDpPart(this._dpTurnPage, this._newRT, EDisplayPart.Left);
                this.updateDpPart(this._dpMainPage, this._newRT, EDisplayPart.Right);

                this.turnAngle = 180;
            }
            break;

            case EDirection.Backward: {
                // 当前页
                this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Right);
                this.updateDpPart(this._dpTurnPage, this._curRT, EDisplayPart.Left);

                // 新一页
                this.updateDpPart(this._dpTurnPage, this._newRT, EDisplayPart.Right);
                this.updateDpPart(this._dpMainPage, this._newRT, EDisplayPart.Left);

                this.turnAngle = 0;
            }
            break;
        }
    }

    turnIng(delta:number) {
        if(this._direction === EDirection.None)
            return;

        let angle = this.turnAngle;
        this.turnAngle += delta;
    }

    turnEnd() {
        if(this._direction === EDirection.None)
            return;

        this._direction = EDirection.None;

        this._dpTurnPage.left.node.active = false;
        this._dpTurnPage.right.node.active = false;

        this._curPageNode = this._newPageNode;
        this._newPageNode = null;

        this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Left);
        this.updateDpPart(this._dpMainPage, this._curRT, EDisplayPart.Right);
    }


    update(dt:number) {
        // return;
        if(this._direction === EDirection.None)
            return;

        let step = 2;
        let preAngle = this.turnAngle;
        switch(this._direction) {
            case EDirection.Forward: {
                this.turnAngle -= step;
            }
            break;

            case EDirection.Backward: {
                this.turnAngle += step;
            }
            break;
        }
        
        if(Math.abs(this.turnAngle - preAngle) <= 0.00001) {
            this.turnEnd();
        }

    }
}
